package pd_server

import (
	"context"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"strings"
	"time"

	"gitee.com/general252/proxy_device/pd_common"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
)

type Server struct {
	conns pd_common.Map[string, *QuicClient]

	httpPort   int
	socks5Port int
}

func NewServer(httpPort int, socks5Port int) *Server {
	return &Server{
		httpPort:   httpPort,
		socks5Port: socks5Port,
	}
}

func (tis *Server) Serve() {
	gin.SetMode(gin.ReleaseMode)
	r := gin.Default()
	r.GET("/api/v1/device/:deviceId", tis.websocketHandle)

	go tis.listenTCP()

	_ = r.Run(fmt.Sprintf(":%v", tis.httpPort))
}

func (tis *Server) listenTCP() {
	tcpListen, err := net.ListenTCP("tcp", &net.TCPAddr{
		Port: tis.socks5Port,
	})
	if err != nil {
		log.Println(err)
		return
	}
	log.Printf("listen tcp %v", tcpListen.Addr())

	for {
		tcpConn, err := tcpListen.Accept()
		if err != nil {
			log.Println(err)
			return
		}

		log.Printf("new tcp conn 收到TCP连接(socks5连接): %v", tcpConn.RemoteAddr())

		go tis.handleTCPConn(tcpConn)
	}
}

//	tcp -> quic -> socks5 -> http
//
// websocket -> quic -> socks5 -> http
// 将 tcp 上的数据转到 websocket 上传输
func (tis *Server) handleTCPConn(tcpConn net.Conn) {
	defer func() {
		_ = tcpConn.Close()
		log.Printf("close tcp conn 关闭TCP连接(socks5连接): %v", tcpConn.RemoteAddr())
	}()

	puId := make([]byte, 20)
	n, err := tcpConn.Read(puId)
	if err != nil {
		log.Println(err)
		return
	}

	strPuId := strings.TrimSpace(string(puId[:n]))
	log.Printf("TCP连接的目标设备ID: %v", strPuId)

	quicClient, ok := tis.conns.Load(strPuId)
	if !ok {
		log.Println("not found quic client")
		return
	}
	log.Println("fond quic client")

	stream, err := quicClient.OpenStream(context.TODO())
	if err != nil {
		log.Printf("quicClient.OpenStream fail, %v", err)
		return
	}
	defer func() {
		_ = stream.Close()
	}()
	log.Println("open stream success. 建立quic流")

	go func() {
		_, _ = io.Copy(tcpConn, stream)
	}()

	_, _ = io.Copy(stream, tcpConn)
}

func (tis *Server) websocketHandle(c *gin.Context) {
	var upGrader = websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}

	deviceId := c.Param("deviceId")
	conn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		log.Println(err)
		return
	}

	conn.SetCloseHandler(func(code int, text string) error {
		log.Printf("close websocket conn: %v", deviceId)

		message := websocket.FormatCloseMessage(code, "")
		_ = conn.WriteControl(websocket.CloseMessage, message, time.Now().Add(time.Second))

		return nil
	})

	cc := pd_common.NewWebSocketPacketConn(conn)
	go func() {
		for {
			time.Sleep(time.Second * 8)
			cc.WritePingMessage()
		}
	}()

	quicClient := NewQuicClient(cc)

	log.Printf("new websocket conn 收到websocket连接: %v", deviceId)
	tis.conns.Store(deviceId, quicClient)
}
